package cn.edu.config;

import cn.edu.filter.MyFilter;
import cn.edu.service.UserService;
import cn.edu.util.JwtUtil;
import cn.edu.vo.ResultVO;
import com.alibaba.fastjson.JSON;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.annotation.Resource;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * @author Mr.ma
 * @since 2023/1/3 20:27
 **/
@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource
    private UserService userService;
    @Resource
    private MyFilter myFilter;

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 指定security过滤器加载前的过滤器
        http.addFilterBefore(myFilter, UsernamePasswordAuthenticationFilter.class);

        // 指定登录界面，并放行相关资源
        http.formLogin()
                .loginProcessingUrl("/login")
                //.loginPage("/login.html")
                //.failureForwardUrl("/fail")
                //.successForwardUrl("/main")
                // 登录成功后的处理器
                .successHandler(successHandler())
                // 登录失败后的处理器
                .failureHandler(failureHandler())
                .permitAll();

        // 权限不足时，跳转链接
        http.exceptionHandling().accessDeniedHandler(deniedHandler());

        // 设置认证后，才可以访问资源
        http.authorizeRequests().anyRequest().authenticated();

        // 禁用跨站伪造请求
        http.csrf().disable();

        // 允许跨域
        http.cors();

    }

    private AuthenticationSuccessHandler successHandler(){
        return (request,response,authentication) -> {
            response.setContentType("json/application;charset=utf-8");
            PrintWriter writer = response.getWriter();

            // 获取当前账户的主要信息
            // import org.springframework.security.core.userdetails.User;
            User user = (User) authentication.getPrincipal();

            // 账户名
            String username = user.getUsername();
            // 账户所拥有的权限
            Collection<GrantedAuthority> authorities = user.getAuthorities();
            // 将权限类型转换成字符串
            List<String> authorityList = authorities.stream().map(item -> item.getAuthority()).collect(Collectors.toList());

            // 创建map集合作为参数，用于生成为token令牌
            Map<String,Object> objectMap = new HashMap<>(16);
            objectMap.put("username",username);
            objectMap.put("authorities",authorityList);

            // 调用JWT工具类中的方法生成token令牌
            String token = JwtUtil.createToken(objectMap);

            // 返回指定格式的JSON数据
            String result = JSON.toJSONString(new ResultVO(2000, "登录成功", token));

            // 将JSON数据返回给前端
            writer.print(result);
            writer.flush();
            writer.close();
        };
    }


    private AuthenticationFailureHandler failureHandler(){
        return (request,response,authenticationException) -> {
            response.setContentType("json/application;charset=utf-8|");
            PrintWriter writer = response.getWriter();
            String result = JSON.toJSONString(new ResultVO(5000, "账号或密码不正确", null));
            writer.print(result);
            writer.flush();
            writer.close();
        };
    }

    /**
     * 自定义的权限不足处理器
     * @return AccessDeniedHandler
     */
    private AccessDeniedHandler deniedHandler(){
        return (request, response, e) -> {
            response.setContentType("json/application;charset=utf-8");
            PrintWriter writer = response.getWriter();
            String result = JSON.toJSONString(new ResultVO(4003, "权限不足", null));
            writer.print(result);
            writer.flush();
            writer.close();
        };
    }
}
